package com.szwistar.common.comm.jsonrpc.udp;

import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Map;

import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.szwistar.common.comm.AsyncResult;
import com.szwistar.common.comm.CommEndpoint;
import com.szwistar.common.comm.ServerBase;
import com.szwistar.common.comm.blocktrans.BlockTransFrameCodec;
import com.szwistar.common.comm.minahttpserver.HttpServer;
import com.szwistar.common.datastruct.Reflector;


interface JsonRpcInvoker {
	/**
	 * 本地调用
	 * @return 返回对象
	 */
	public AsyncResult call(String target, String methodName, Object[] params);

	/**
	 * JSON-RPC 调用
	 * @return RPC结果
	 */
	JsonRpcResult call(JsonRpcRequest req);
}

public class JsonRpcService implements JsonRpcInvoker {
	static final Logger LOG = LoggerFactory.getLogger(JsonRpcService.class);

	static {
		// 注册净荷类型
		BlockTransFrameCodec.registerPayloadType(JsonRpcRequest.TYPEID, JsonRpcRequest.class);
		BlockTransFrameCodec.registerPayloadType(JsonRpcResult.TYPEID, JsonRpcResult.class);
	}

	// 对象ID<->对象 映射表
	Map objs;
	// 服务名称<->服务类 映射表
	Map<String, Class<?>> svcs = new HashMap<String, Class<?>>();

	/**
	 * 注册对象ID<->对象 映射表
	 * @param objs
	 */
	public void registerObjectMap(Map objs) {
		this.objs = objs;
	}

	/**
	 * 注册服务
	 */
	public void registerService(String serviceName, Class<?> serviceClazz) {
		svcs.put(serviceName, serviceClazz);
	}

	/**
	 * 本地调用
	 */
	@Override
	public AsyncResult call(String target, String methodName, Object[] params) {
		Integer objId = null;
		Object pThis = null;
		Class<?> clazz = null;

		try { objId = Integer.parseInt(target); } catch(Exception e) {}
		if(objId != null) {
			// 查找对应的对象
			pThis = objs.get(objId);
			if(pThis == null) { return new AsyncResult(JsonRpcResult.NO_OBJECT); }
			clazz = pThis.getClass();
		} else {
			// 查找对应的服务类
			clazz = svcs.get(target);
			if(clazz == null) { return new AsyncResult(JsonRpcResult.NO_SERVICE); }
		}

		try {
			// 调用方法
			Object ret = Reflector.call(clazz, pThis, methodName, params);

			// 处理返回值
			if(ret instanceof AsyncResult) {
				return (AsyncResult) ret;
			} else {
				return new AsyncResult<Object>(JsonRpcResult.OK, null, ret);
			}
		} catch(Exception e) {
			LOG.error("RPC 调用失败！", e);
			return new AsyncResult<String>(JsonRpcResult.EXCEPTION, e.toString());
		}
	}

	@Override
	public JsonRpcResult call(JsonRpcRequest req) {
		AsyncResult ret = call(req.target, req.method, req.params);

		//
		// 把 AsyncResult 翻译成 JsonRpcResult
		//
		if(ret.isDone()) {
			// 如果已经完成，则直接返回结果
			return new JsonRpcResult(req, ret);
		} else {
			return new JsonRpcResult(req, ret);
		}
	}

	/**
	 * Server Accept 进来的客户端
	 * @author 深圳市智辰科技有限公司 张勇
	 */
	public static final class JsonRpcServerClient implements CommEndpoint {
		IoSession session;
		JsonRpcInvoker server;

		@Override
		public IoSession getSession() {
			return session;
		}

		@Override
		public void close() {
			if(session == null) { return; }
			if(session.isConnected()) {	session.close(true); }
			session = null;
		}

		@Override
		public SocketAddress getLocalAddress() {
			if(session == null) { return null; }
			return session.getLocalAddress();
		}

		@Override
		public SocketAddress getPeerAddress() {
			if(session == null) { return null; }
			return session.getRemoteAddress();
		}

		@Override
		public WriteFuture write(Object message) {
			if(session == null) { return null; }
			return session.write(message);
		}

		@Override
		public boolean isConnected() {
			if(session == null) { return false; }
			return session.isConnected();
		}

		@Override
		public void onCreate(IoSession session, Object owner) throws Exception {
			this.session = session;
			this.server = (JsonRpcInvoker) owner;
		}

		@Override
		public void onOpened() {
		}

		@Override
		public void onMessageSent(Object message) {
		}

		@Override
		public void onMessageReceived(Object message) {
			JsonRpcResult ret = server.call((JsonRpcRequest)message);
			write(ret);
			LOG.debug("RPC 返回: {}", ret.toString());
		}

		@Override
		public void onClosed() {
			session = null;
			// TODO RPC 客户端关闭时发出通知
		}

		@Override
		public void onIdle(IdleStatus status) {
			// TODO RPC 客户端长时间不通信就关闭？
		}

		@Override
		public void onExceptionCaught(Throwable cause) {
			LOG.error("JsonRpcServerClient 遇到异常：", cause);
		}
	}

	/**
	 * JSON RPC HTTP 服务器
	 * @author 深圳市智辰科技有限公司 张勇
	 */
	public static final class JsonRpcHttpServer extends HttpServer {
		JsonRpcService svc;

		public JsonRpcHttpServer(String host, int port, JsonRpcService svc) {
			this.svc = svc;
		}
	}

	public void startTcpServer(String host, int port) {
		ServerBase<JsonRpcServerClient> server = new ServerBase<JsonRpcServerClient>("TCP JsonRpc", port, JsonRpcServerClient.class, this, true);
        server.getAcceptor().getFilterChain().addLast("jsonRpcCodec", BlockTransFrameCodec.newFilter());
		server.start();
	}

	public void startUdpServer(String host, int port) {
		ServerBase<JsonRpcServerClient> server = new ServerBase<JsonRpcServerClient>("UDP JsonRpc", port, JsonRpcServerClient.class, this, false);
        server.getAcceptor().getFilterChain().addLast("jsonRpcCodec", BlockTransFrameCodec.newFilter());
		server.start();
	}

	public void startHttpServer(String host, int port) throws Exception {
		JsonRpcHttpServer server = new JsonRpcHttpServer(host, port, this);
		server.run();
	}
}
